Segments split the ELF binary into parts which are then loaded into memory by the OS programme loader. They can be thought of as grouping sections by their attributes and only selecting those which will be loaded into memory. In essence, segments contain information needed at runtime, while sections contain information needed at link-time.
Segments are described by programme headers which are stored in the Programme Header Table (PHT). These structs are again defined in <elf.h>:
typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
typedef struct
{
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;
p_type - describes the type of the segment.p_offset - the offset from the beginning of the file where the segment resides.p_vaddr - the virtual address at which the segment resides in memory.p_paddr - the segment's physical address, which is relevant only for systems with physical addressing. This member holds unspecified contents for executables and shared objectsp_filesz - the number of bytes the segment occupies in the file image. It may be 0.p_memsz - the number of bytes the segment occupies in the memory image. It may be 0.p_align - the value to which the segments are aligned in the file and in memory. If this holds 0 or 1, then no alignment is required. Otherwise, p_align should be a positive integer power of 2 and p_vaddr should be equal to p_offset % p_align.The PHT can be viewed by specifying the -l argument to readelf:
| Name | Value |
|---|---|
PT_NULL |
0 |
PT_LOAD |
1 |
PT_DYNAMIC |
2 |
PT_INTERP |
3 |
PT_NOTE |
4 |
PT_SHLIB |
5 |
PT_PHDR |
6 |
PT_TLS |
7 |
PT_LOOS |
0x60000000 |
PT_HIOS |
0x6fffffff |
PT_LOPROC |
0x70000000 |
PT_HIPROC |
0x7fffffff |
PT_LOADThis specifies a loadable segment described by p_filesz and p_memsz which means the segment is going to be mapped into memory. Bytes from the file are mapped to the beginning of the memory segment. Should the memory size be larger than the file size, the extra bytes are filled with 0s and are placed after the segment's data. Note that the file size cannot be larger than the memory size.
Entries of this type are sorted in an ascending order in the PHT according to their p_vaddr field.
All executable files must contain at least one PT_LOAD segment.
PT_DYNAMICThe dynamic segment is pertinent to executables which avail themselves of dynamic linking and contains information for the dynamic linker. It typically points to the .dynamic section and comprises a series of structures which hold the relevant information.
typedef struct
{
Elf32_Sword d_tag; /* Dynamic entry type */
union
{
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Address value */
} d_un;
} Elf32_Dyn;
typedef struct
{
Elf64_Sxword d_tag; /* Dynamic entry type */
union
{
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
} Elf64_Dyn;
In essence, the d_tag field determines whether the d_un field is treated as a value or an address.
PT_NOTEThis segment is completely optional and may contain information that is pertinent to a specific system. It can hold a variable number of entries of size 4 or 8 bytes on 32-bit and 64-bit platforms, respectively.
PT_INTERPHere are specified the location and size of a null terminated string which describes the programme interpreter. Only one such segment is allowed per file and it must also precede any PT_LOAD segments.
PT_PHDRThis segment contains the location and size of the Programme Header Table itself, both in the file and in memory. Similarly to PT_INTERP, only one such segment is allowed per file and it must also precede any PT_LOAD segments.
PT_TLSThis segment specifies the Thread-Local Storage template. The latter is an amalgamation of all sections of type SHF_TLS. TLS sections are used to specify the size and initial contents of data whose copies are to be associated with different threads of execution. The part of the TLS which holds this initialised data is referred to as the TLS initialisation image, while the rest of the template is comprised of one or more sections of type SHF_NOBITS.
| Member | Value |
|---|---|
p_offset |
File offset of the TLS initialization image |
p_vaddr |
Virtual memory address of the TLS initialization image |
p_paddr |
reserved |
p_filesz |
Size of the TLS initialization image |
p_memsz |
Total size of the TLS template |
p_flags |
PF_R |
p_align |
Alignment of the TLS template |
PT_SHLIB is reserved but is unspecified, while values from PT_LOOS to PT_HIOS and from PT_LOPROC through PT_HIPROC are reserved for OS- and processor-specific semantics, respectively.
The p_flags field describes the permissions the segment is equipped with. It is important to note that the system may actually give more access than requested with the exception that a segment will never be assigned write permissions, unless explicitly requested:
| Flags | Value | Exact | Allowable |
|---|---|---|---|
| none | 0 | All access denied | All access denied |
PF_X |
1 | Execute only | Read, execute |
PF_W |
2 | Write only | Read, write, execute |
PF_W+PF_X |
3 | Write, execute | Read, write, execute |
PF_R |
4 | Read only | Read, execute |
PF_R+PF_X |
5 | Read, execute | Read, execute |
PF_R+PF_W |
6 | Read, write | Read, write, execute |
PF_R+PF_W+PF_X |
7 | Read, write, execute | Read, write, execute |